<!--
 * @Author: wangzz wangzhuang@outlook.com
 * @Date: 2023-06-01 16:32:43
 * @LastEditors: wangzz wangzhuang@outlook.com
 * @LastEditTime: 2023-06-05 15:37:51
 * @FilePath: \FrontBasicSpace\vue3-minemap-boot\src\pages\minemap\index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
    <div class="container">
        <div class="card-panel card-panel-top-right">
            <div class="card-title" style="font-weight: 900;">地图加载时长测试</div>
            <div class="card-item" style="min-width: 215px;">
                <p id="result-info01"> 页面加载完成总时长:<span id='result-text1' style="color: red;">0</span>s </p>
                <p>地图资源加载总时长：<span id='result-text2' style="color: red;">0</span>s</p>
                <p>地图加载并渲染完成总时长：<span id='result-text3' style="color: blue;">0</span>s</p>
            </div>
        </div>
        <!-- <div class="card-panel card-panel-top-left">
            <div class="card-json-info">
                <div class="title">详细数据信息</div>
                <div class="info">
                    <pre id="json-renderer" class="json-body"></pre>
                </div>
            </div>
        </div> -->
        <div id="map">
            <div id="edit-ctrl-group" class="edit-ctrl-group">
                <div class="edit-btn" title="画点" @click="onEditBtnClick('point')">
                    <span class="iconfont icon-draw-point" />
                </div>
                <div class="edit-btn" title="'画线'" @click="onEditBtnClick('line')">
                    <span class="iconfont icon-draw-point" />
                </div>
                <div class="edit-btn" title="画圆弧" @click="onEditBtnClick('arc')"><span class="iconfont icon-draw-curve" />
                </div>
                <div class="edit-btn" title="画多边形" @click="onEditBtnClick('polygon')"><span
                        class="iconfont icon-draw-polygon1" /></div>
                <div class="edit-btn" title="画矩形" @click="onEditBtnClick('rectangle')"><span
                        class="iconfont icon-draw-square" /></div>
                <div class="edit-btn" title="画三角形" @click="onEditBtnClick('triangle')"><span
                        class="iconfont icon-Triangle" /></div>
                <div class="edit-btn" title="画圆" @click="onEditBtnClick('circle')"><span
                        class="iconfont icon-draw-circle" /></div>
                <div class="edit-btn" title="删除所选" @click="onEditBtnClick('trash')"><span
                        class="iconfont icon-tool-delete" /></div>
                <div class="edit-btn" title="撤销上一步操作" @click="onEditBtnClick('undo')">
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>

const state = reactive({
    map: null, // 地图实例对象
    edit: null, // 编辑实例对象
    performance: window.performance,
    loadStartTime: undefined,
    markers: [], // 点标记
    projection: 'EPSG:3857' //设置投影方式为Web墨卡托投影
})

onMounted(() => {
    state.loadStartTime = state.performance ? state.performance.now() : new Date().getTime();
    initMapInstance();
})

const initMapInstance = () => {
    state.map = new minemap.Map({
        container: 'map',
        style: 'https://service.minedata.cn/map/solu/style/11001', // 底图样式
        center: [121.90154, 29.46968],
        zoom: 12, // 默认缩放层级
        pitch: 0, // 地图俯仰角度
        maxZoom: 17, // 地图最大缩放等级
        minZoom: 3, // 地图最小缩放等级
        markerTempCoordinates: [118.78960, 32.09380],
        coordinateSystem: 'bd09' // 设置为百度坐标系
    });
    // 地图资源加载完成后会触发load事件
    state.map.on('load', () => {
        /**
         * 如果地图数据加载并渲染完成后调用map.isStyleLoaded()会返回true否则返回false
         */
        const sourceLoadTime = state.performance ? state.performance.now() : new Date().getTime();
        document.getElementById('result-text2').innerText = ((sourceLoadTime - state.loadStartTime) / 1000).toFixed(2);
        if (state.map && state.map.isStyleLoaded()) {
            const totalLoadTime = state.performance ? state.performance.now() : new Date().getTime();
            console.log(`output-> 地图加载并渲染完成总时长：${((totalLoadTime - state.loadStartTime) / 1000).toFixed(2)}s`);
            document.getElementById('result-text3').innerText = ((totalLoadTime - state.loadStartTime) / 1000).toFixed(2);
            // 设置地图边界
            fitBoundingBox();
            const lngLat = new minemap.LngLat(118.7798958857, 32.087470954524);
            addCustomMarker(lngLat);
            addDefaultMarker(lngLat);
            addEditControl();
            drawCircle();
            // 增加自定义数据源、自定义图层
            addSources();
            addLayers();
            $("#json-renderer").jsonViewer([], { collapsed: true });
            state.map.on('click', function (e) {
                var features = state.map.queryRenderedFeatures(e.point, { layers: ['cluster-0', 'cluster-1', 'cluster-2'] });
                var feature = features.length > 0 ? features[0] : null;

                // 如果开启显示详细信息功能
                // 将features数组详情信息存入properties.children中
                var source = state.map.getSource("data-point");
                features = features.map(function (f) {
                    if (feature.properties.cluster_id && feature.properties.point_count) {
                        /*  获取下一层级的children
                         * @param cluster_id属性值
                         * @param callback 回调函数 (`(error, features) => {}`)
                        */
                        // source.getClusterChildren(feature.properties.cluster_id, function (err,res) {
                        //     /* res 返回下一层级的children信息 */
                        // });

                        /*  获取当前聚合点的所有children信息
                         * @param cluster_id属性值
                         * @param limit 返回数量限制，默认为10，
                         * @param offset 分页显示起始值，默认为0
                         * @param callback 回调函数 (`(error, features) => {}`)
                         */
                        source.getClusterLeaves(feature.properties.cluster_id, feature.properties.point_count, 0, function (err, res) {
                            f.properties.children = res;
                        });
                    }
                    return f;
                });

                var dataInfo = features.map(function (f) {
                    return {
                        type: f.type,
                        properties: f.properties,
                        layer: f.layer
                    }
                });
                // 界面显示数据
                $("#json-renderer").jsonViewer(dataInfo, { collapsed: true });
            })
        }
        // 地图操作控件 =》 放大、缩小、比例尺等
        state.map.addControl(new minemap.Navigation(), 'bottom-right');
        // state.map.addControl(new minemap.Scale(), 'top-right');
        state.map.addControl(new minemap.Fullscreen(), 'top-left');

        // 禁止地图拖动
        // state.map.dragPan.disable();
    });
}

const delEditControl = () => {
    if (state.map && state.edit) {
        state.edit.dispose();
        state.edit = null;
        document.getElementById('edit-ctrl-group').style.display = 'none';
    }
}

const addEditControl = () => {
    delEditControl();
    if (state.map) {
        // 初始化地图编辑器
        state.edit = new minemap.edit.init(state.map, {
            boxSelect: true, // 是否支持拉宽选择
            touchEnabled: true, // 是否支持手指触屏
            displayControlsDefault: true, // 是否启动编辑控件
            showButtons: false, // 是否启动默认控件按钮
            secondEdit: false, // 是否启用二次编辑
        });
        document.getElementById('edit-ctrl-group').style.display = 'block';
    }
}

const onEditBtnClick = (mode) => {
    if (state.edit && mode) {
        state.edit.onBtnCtrlActive(mode);
    }
}

window.onerror = function (errorMessage, scriptURI, lineNumber, columnNumber, errorObj) {
    if (scriptURI.indexOf('minemap-edit') > -1) {
        message.error(errorObj.message);
    }
};

// 设置地图边界范围
const fitBoundingBox = () => {
    if (state.map) {
        // 经纬度矩形边界为一个矩形的经纬度范围，用西南角和东北角的两个经纬度来描述，这两个经纬度分别代表边界的最小值和最大值；
        const bounds = [[118.76573, 32.07462], [118.80301, 32.09360]]
        state.map.fitBounds(bounds);
    }
}


const addCustomMarker = (lngLat) => {
    if (state.map) {
        let el = document.createElement('div');
        el.id = 'marker';
        el.style["background-image"] = "url(https://minedata.cn/nce-static/support/demo/js-api/zh/images/park-blue2x.png)";
        el.style["background-size"] = "cover";
        el.style.width = "24px";
        el.style.height = "38px";
        el.style["border-radius"] = "20%";
        // Marker构造函数存在两个参数，1. 自定义DOM元素 2. Object参数（偏移量）
        // offset参数：标注点相对于其左上角偏移像素大小，调用setLngLat方法指定Marker的坐标位置
        const _marker = new minemap.Marker(el, { offset: [-12, -38] }).setLngLat(lngLat).addTo(state.map);
        state.markers.push(_marker);
    }
}

const addDefaultMarker = (lngLat) => {
    if (state.map) {
        var defaultMarker = new minemap.Marker({
            draggable: true, // 在初始化的时候决定是否可以拖拽
            anchor: 'top-left', // 锚点位置（默认：top-left)： center、top、bottom
            color: 'red', // 默认marker标记的颜色
            rotation: 0, // marker的旋转角度，以锚点作为旋转中心，顺时针为正
            pitchAlignment: 'map', // 倾斜对齐参数（默认值：auto）
            scale: 1, // 只有默认标记存在这个参数，将默认标记放大1.5倍
        })
            .setLngLat([lngLat.lng + 0.05, lngLat.lat])
            .addTo(state.map);
        state.markers.push(defaultMarker);
    }
}
/**
 * 使用经纬度坐标和半径生成圆
 * center 中心点
 * radius 半径
 * steps 边的数量，数量越多越规整，默认值为64 非不输项
 * units 半径单位 miles，kilometers，degree，radians
 * geojson
 */
const drawCircle = () => {
    let center = [119.42400062113, 32.188603916188];
    let radius = 0.5;
    let options = {
        steps: 64,
        units: 'kilometers',
        properties: {
            foo: 'bar'
        }
    }
    const CIRCLE_DATA = turf.circle(center, radius, options);
    // 增加自定义数据源、自定义图层
    state.map.addSource('polygonSource', {
        'type': 'geojson',
        'data': CIRCLE_DATA,
    })
    state.map.addLayer({
        'id': 'polygonLayer',
        'type': 'fill',
        'source': 'polygonSource',
        'layout': {},
        'paint': {
            'fill-color': 'blue',
            'fill-opacity': 0.6,
        }
    })
}

/**
 * 点聚合显示详细信息
 */

const addSources = () => {
    state.map.addSource('data-point', {
        type: 'geojson',
        data: 'https://minedata.cn/nce-static/support/demo/js-api/zh/assets/poi_suzhou.json',
        cluster: true,
        clusterMaxZoom: 15, // 最大聚合层级
        clusterRadius: 50, // 聚合半径
    })
}

const addLayers = () => {
    //添加非聚合图层
    state.map.addLayer({
        "id": "unclustered-points",
        "type": "symbol",
        "source": "data-point",
        "filter": ["!has", "point_count"],
        "layout": {
            "icon-image": "star-11"
        }
    });

    //添加聚合图层
    var layers = [[1000, 'rgba(241, 128, 23, 0.6)'], [100, 'rgba(240, 194, 12, 0.6)'], [0, 'rgba(110, 204, 57, 0.6)']];

    layers.forEach(function (layer, i) {
        state.map.addLayer({
            "id": "cluster-" + i,
            "type": "circle",
            "source": "data-point",
            "paint": {
                "circle-color": layer[1],
                "circle-radius": 18
            },
            "filter": i === 0 ?
                [">=", "point_count", layer[0]] :
                ["all", [">=", "point_count", layer[0]], ["<", "point_count", layers[i - 1][0]]]
        });
    });
    //添加数量图层
    state.map.addLayer({
        "id": "cluster-count",
        "type": "symbol",
        "source": "data-point",
        "layout": {
            "text-field": "{point_count}",
            "text-size": 10
        },
        "paint": {
            "text-color": "rgba(0,0,0,.75)"
        },
        "filter": ["has", "point_count"]
    });
}




// 销毁地图
onBeforeUnmount(() => {
    if (state.map) {
        state.map.remove();
        state.map = null;
    }
})
</script>

<style lang="scss" scoped>
html,
body {
    margin: 0;
    padding: 0;
}

.container {
    height: 100vh;
    width: 100vw;
    margin: 0;
    padding: 0;

    #map {
        width: 100%;
        height: 100%;
    }

    .edit-ctrl-group {
        position: absolute;
        z-index: 300;
        top: 150px;
        right: 10px;
        width: 32px;
        overflow: hidden;

        .edit-btn {
            width: 30px;
            height: 30px;
            line-height: 30px;
            font-size: 14px;
            vertical-align: middle;
            text-align: center;
            cursor: pointer;
            color: #111;
            background-color: white;
            border: 1px solid #ddd;
        }

        .edit-btn:hover {
            background-color: #efefef;
        }
    }
}
</style>